package cn.com.linht.jsontosql.entity;

import cn.com.linht.jsontosql.util.Assert;
import net.sf.jsqlparser.util.validation.Validation;
import net.sf.jsqlparser.util.validation.ValidationError;
import net.sf.jsqlparser.util.validation.feature.DatabaseType;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 查询的entity
 *
 * @author linht
 */
public class SelectVO {
    /**
     * 查询处理过程
     */
    private List<OperatorVO> operatorList;
    /**
     * 原始表
     */
    private List<OriginalTableVO> originalTableList;
    /**
     * 整个查询的过滤条件
     */
    private List<QueryCriteriaVO> queryCriteriaList;

    /**
     * 最后执行的算子id
     */
    private String lastOperatorId;

    public List<QueryCriteriaVO> getQueryCriteriaList() {
        return queryCriteriaList;
    }

    public List<OperatorVO> getOperatorList() {
        return operatorList;
    }

    public void setOperatorList(List<OperatorVO> operatorList) {
        this.operatorList = operatorList;
    }

    public List<OriginalTableVO> getOriginalTableList() {
        return originalTableList;
    }

    public void setOriginalTableList(List<OriginalTableVO> originalTableList) {
        this.originalTableList = originalTableList;
    }

    public String getLastOperatorId() {
        return lastOperatorId;
    }

    public void setLastOperatorId(String lastOperatorId) {
        this.lastOperatorId = lastOperatorId;
    }

    @Override
    public String toString() {
        return "SelectVO{" +
                "operatorList=" + operatorList +
                ", originalTableList=" + originalTableList +
                ", queryCriteriaList=" + queryCriteriaList +
                '}';
    }

    public void setQueryCriteriaList(List<QueryCriteriaVO> queryCriteriaList) {
        this.queryCriteriaList = queryCriteriaList;
    }


    /**
     * 校验最后算子Id是否存在算子里
     *
     * @return
     */
    public void checkIdIsExistsList() {
        Assert.isTrue(StringUtils.isNotBlank(lastOperatorId), "id为空");
        boolean contains = OperatorVO.getIdList(operatorList).contains(lastOperatorId);
        Assert.isTrue(contains, "最后算子Id不存在算子集合中");
    }

    /**
     * 将其转换成sql
     * 1、校验算子是否存在
     * 2、转换table为sql的
     *
     * @return
     */
    public String transformSql() {
        this.checkIdIsExistsList();
        Map<String, String> map = new HashMap<>(16);
        originalTableList.forEach(e -> {
            map.put(e.getId(), e.transformSql());
        });
        while (!map.containsKey(lastOperatorId)) {
            boolean isExist = false;
            for (OperatorVO operatorVO : operatorList) {
                if (operatorVO.containsKey(map)) {
                    map.put(operatorVO.getId(), operatorVO.transformSql(map));
                    isExist = true;
                }
            }
            Assert.isTrue(isExist, "算子的输入不存在，请自查");
        }
        String result = map.get(lastOperatorId);
        //填充全局过滤条件
        result = OperatorVO.fillFilter(result, QueryCriteriaVO.listToMap(this.queryCriteriaList));
        //校验sql是否正确
        checkSql(result);
        return result;
    }

    /**
     * 校验sql
     *
     * @param sql
     */
    public void checkSql(String sql) {
        Validation validation = new Validation(Arrays.asList(DatabaseType.SQLSERVER, DatabaseType.MARIADB,
                DatabaseType.POSTGRESQL, DatabaseType.H2), sql);
        List<ValidationError> errors = validation.validate();
        Assert.isTrue(CollectionUtils.isEmpty(errors), errors.toString());
    }

}
